package edu.iastate.cs228.hw1;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import edu.iastate.cs228.hw1.Animal.Gender;
/**
 * This class tests all of the methods of the Ecosystem project
 * @author Devon Eilers
 *
 */
public class EcosystemSimTest 
{
	/**
	 * Sets the RandomSingleton seed for consistent results
	 */
	@Before
	public void setSeed()
	{
		RandomSingleton.getInstance().setSeed(123456789);
	}
	
	/**
	 * Tests the abstract animal class getAge() method
	 */
	@Test
	public void testAnimalGetAge()
	{
		Animal bear = new Bear(7, Gender.MALE);
		Animal fish = new Fish(3, Gender.FEMALE);
		
		assertEquals(7, bear.getAge());
		assertEquals(3, fish.getAge());
	}
	
	/**
	 * Tests the correctness of the Bear constructor
	 */
	@Test
	public void testBearConstructor() 
	{
		// constructs a new male bear with age 0
		Bear bear = new Bear(0, Animal.Gender.MALE);
		
		
		// check age
		assertEquals(0, bear.age);
		// check gender
		assertEquals(Animal.Gender.MALE, bear.gender);
	}
	
	/**
	 * Tests the correctness of the Bear constructor with random age and gender
	 */
	@Test
	public void testRandomBearConstructor()
	{
		Bear bear = new Bear();
		// check age
		assertEquals(0, bear.getAge());
		// check strength
		assertEquals(1, bear.getStrength());
		// check gender
		assertEquals(Gender.FEMALE, bear.gender);
	}
	
	/**
	 * Tests if the getStrength() method of Bear produces correct results
	 */
	@Test
	public void testBearStrength()
	{
		Bear bear;
		int[] correctStrengthArr = {1, 2, 3, 4, 5, 4, 3, 2, 1, 0};
		
		for(int i = 0; i < 10; ++i)
		{
			bear = new Bear(i, Animal.Gender.MALE);
			
			// test strength
			assertEquals(correctStrengthArr[i], bear.getStrength());
		}
	}
	
	/**
	 * Tests if the toString() method of Bear produces correct results
	 */
	@Test
	public void testBearToString()
	{
		Bear bear = new Bear (0, Animal.Gender.MALE);
		
		// test male bear of age 0
		assertEquals("BM0", bear.toString());
		bear = new Bear (3, Animal.Gender.FEMALE);
		
		// test female bear of age 3
		assertEquals("BF3", bear.toString());
	}

	/**
	 * Tests if the incrAge() method of Bear produces correct results
	 */
	@Test
	public void testBearIncrAge()
	{
		Bear bear = new Bear(0, Animal.Gender.MALE);
		
		// makes sure the method returns true in the normal case
		assertTrue(bear.incrAge());
		// test correct age incrementation
		assertEquals(1, bear.age);
		
		// bear with max age
		bear = new Bear (9, Animal.Gender.MALE);
		
		// this should return false if correct
		assertFalse(bear.incrAge());
		// age should not increase
		assertEquals(9, bear.age);
	}
	
	/**
	 * Tests the maxAge() function of Bear for correct results
	 */
	@Test
	public void testBearMaxAge()
	{
		Bear bear = new Bear(9, Animal.Gender.MALE);
		
		// max age for Bear should be 9
		assertTrue(bear.maxAge());
		
		bear = new Bear (4, Animal.Gender.MALE);
		
		// this bear is not at max age
		assertFalse(bear.maxAge());
	}
	
	/**
	 * Tests the Fish constructor for correctness
	 */
	@Test
	public void testFishConstructor()
	{
		Fish fish = new Fish(3, Gender.MALE);
		
		// check age
		assertEquals(3, fish.age);
		// check gender
		assertEquals(Gender.MALE, fish.gender);
	}
	
	@Test
	public void testRandomFishConstructor()
	{
		Fish fish = new Fish();
		
		// check age
		assertEquals(0, fish.age);
		// check gender
		assertEquals(Gender.FEMALE, fish.gender);
		
	}
	/**
	 * Tests the maxAge() function of Fish for correct results
	 */
	@Test
	public void testFishMaxAge()
	{
		// fish is at max age
		Fish fish = new Fish(4, Gender.MALE);
		
		// max age for Fish should be 4
		assertTrue(fish.maxAge());
		
		fish = new Fish(0, Gender.MALE);
		
		// this fish is not at max age
		assertFalse(fish.maxAge());
	}
	
	/**
	 * Tests the incrAge() function of Fish for correct results
	 */
	@Test
	public void testFishIncrAge()
	{
		Fish fish = new Fish(0, Gender.MALE);
		
		// should increment normally and return true
		
		boolean b = fish.incrAge();
		
		// returns true and increments normally
		assertTrue(b);
		assertEquals(1, fish.getAge());
		
		fish = new Fish(4, Gender.FEMALE);
		
		// should be false
		b = fish.incrAge();
		
		// returns false and does not increment
		assertFalse(b);
		assertEquals(4, fish.age);
	}
	
	/**
	 * Tests the toString() method of Fish for correct results
	 */
	@Test
	public void testFishToString()
	{
		
		Fish fish = new Fish(2, Gender.MALE);
		assertEquals("FM2", fish.toString());
		
		fish = new Fish(3, Gender.FEMALE);
		
		assertEquals("FF3", fish.toString());
	}
	
	/**
	 * Tests the getLength() method of River for correct results
	 */
	@Test
	public void testRiverGetLength()
	{
		River river = new River(10);
		
		// returns correct length
		assertEquals(10, river.getLength());
	}
	
	/**
	 * Tests the addRandom() method for correct results
	 */
	@Test
	public void testRiverAddRandom()
	{
		River river = new River(10);
		
		assertTrue(river.addRandom(new Bear(5, Gender.MALE)));
		
		// this should be filled with a new animal
		assertFalse(river.river[2]==null);
		// makes sure age is changed to zero
		assertEquals(0, river.river[2].age);
		
		River fullRiver = new River(3);
		Animal[] fullArr = {new Fish(), new Fish(), new Fish()};
		
		fullRiver.river = fullArr.clone();
		// should not add anything and return false
		assertFalse(fullRiver.addRandom(new Bear(5, Gender.MALE)));
		
	}
	
	/**
	 * Tests the numEmpty() method for correct results
	 */
	@Test
	public void testRiverNumEmpty()
	{
		River river = new River(3);
		
		// none empty
		Animal[] animals = {new Bear(), new Bear(), new Bear()};
		river.river = animals.clone();
		assertEquals(0, river.numEmpty());
		
		// one empty
		Animal[] animals2 = {new Bear(), null, new Bear()};
		river.river = animals2.clone();
		assertEquals(1, river.numEmpty());
		
		// all empty
		Animal[] animals3 = {null,null,null};
		river.river = animals3.clone();
		assertEquals(3, river.numEmpty());
	}
}
